/* ############################################################### */
/* ############################################################### */
/* ### IOMD RAMCTLC : RAM Control signal generation            ### */
/* ###                                                         ### */
/* ### Created 28/8/92 AS                                      ### */
/* ###                                                         ### */
/* ### 02/09/92: AS: Latch address using ras rather than rclk  ### */
/* ### 03/09/92: AS: Add refresh counter and requester logic   ### */
/* ### 03/09/92: DF: change REFRQ acknowledge logic            ### */
/* ### 17/09/92: AS: Ensure Ndt and Nwe don't go off in refresh ## */
/* ############################################################### */

#include <Handy.h>
#include "ramctl.h"
#include "busarb.h"

#define RAMCTLC_def "RAMCTLC(\
  {IN}  rclk,\
  {IN}  clk32,\
  {IN}  Ninit,\
  {IN}  dah[],\
  {IN}  dal[],\
  {IN}  ah[], \
  {IN}  al[],\
  {IN}  ramreg,\
  {IN}  progstrb,\
  {IN}  la2,\
  {IN}  dwrite,\
  {IN}  lwrite,\
  {IN}  dsize[],\
  {IN}  Nbw,\
  {IN}  dmagoing,\
  {IN}  dmach[],\
  {IN}  refcres,\
  {IN}  ras,\
  {IN}  cas,\
  {IN}  rras[],\
  {IN}  vras,\
  {IN}  colmux,\
  {IN}  split,\
  {IN}  refcyc,\
  {OUT} addl[],\
  {OUT} size[],\
  {OUT} Nras[],\
  {OUT} Nvras,\
  {OUT} Nwe[],\
  {OUT} Ndt[],\
  {OUT} dsf,\
  {OUT} refrq,\
  {OUT} ramc[],\
  {IO}  d[])"

typedef struct {
  ModelCore model;
  
  Signal *rclk, *clk32, *Ninit;
  Bundle *dah, *dal, *ah, *al;
  Signal *ramreg, *progstrb, *la2, *dwrite, *lwrite;
  Bundle *dsize;
  Signal *Nbw, *dmagoing;
  Bundle *dmach;
  Signal *refcres, *ras, *cas;
  Bundle *rras;
  Signal *vras, *colmux, *split, *refcyc;
  Bundle *addl, *size, *Nras;
  Signal *Nvras;
  Bundle *Nwe, *Ndt;
  Signal *dsf, *refrq;
  Bundle *ramc, *d;
} ModelOfRAMCTLC;

typedef struct {
  int dt_ras, dt_cas, dt_we, dt_dt, dt_dsf, dt_regs, dt_ramc;
  int addll;
  int refcount, refrq;
  int ramcr, vrefcr;
} RAMCTLCState;

static void RAMCTLC_proc(void *ModelInst) {

  ModelOfRAMCTLC *me = (ModelOfRAMCTLC *)ModelInst;
  RAMCTLCState *s = me->model.state;

  static int add_h, add_l, write;

/* Programmable registers */
  if (HI(ramreg) && HI(progstrb)) {
    if HI(lwrite) { 
      if HI(la2) 
        s->vrefcr = BINVAL(d) & 0xe9;
      else
        s->ramcr = BINVAL(d) & 0xff;
    } else {
      if HI(la2)
        BundleEvt(d, s->vrefcr, s->dt_regs);
      else
        BundleEvt(d, s->ramcr, s->dt_regs);
    }
  }
  if (FALLING(progstrb) && LO(lwrite)) BundleZZZ(d, s->dt_regs);

/* DMA/ARM access multiplexers */
  if LO(dmagoing) {
    if LO(ras) {
      add_h = BINVAL(ah);
      BundleEvt(size, LO(Nbw), 5*NS);

/* RAM vram/dram 2-level mux */
    BundleEvt(ramc,
     ((add_h & 4) ? 0x3 & (s->ramcr>>((add_h & 3)*2))
                  : 0x7 & (s->vrefcr>>5)), s->dt_ramc);
    }
    if LO(rclk) s->addll = BINVAL(al);
    write = HI(lwrite);
  } else {
    if LO(ras) {
      add_h = BINVAL(dah);
      BundleEvt(size, BINVAL(dsize), 5*NS);
/* RAM vram/dram 2-level mux */
      BundleEvt(ramc,
       ((add_h & 4) ? (0x3 & (s->ramcr>>((add_h & 3)*2)))
                    : 0x7 & (s->vrefcr>>5)), s->dt_ramc);
                   
    }
    if LO(rclk) s->addll = BINVAL(dal);
    write = HI(dwrite);
  }
  if LO(cas) {
    add_l = s->addll;         
    BundleEvt(addl, add_l, 5*NS);
  }

 /* RAS generation */
  if HI(refcyc) {
    BundleEvt(Nras, ~BINVAL(rras), s->dt_ras);
    SignalEvt(Nvras, LO(vras), s->dt_ras);
  } else {
    if HI(ras) {
      if (add_h & 4) {
        BundleEvt(Nras, ~(1<<(add_h & 3)), s->dt_ras);
        SignalEvt(Nvras, ONE, s->dt_ras);
      } else {
        SignalEvt(Nvras, ZERO, s->dt_ras);
        BundleEvt(Nras, 0xf, s->dt_ras);
      }
    } else {
      BundleEvt(Nras, 0xf, s->dt_ras);
      SignalEvt(Nvras, ONE, s->dt_ras);
    }
  }

/* dt/we/dsf generation */
  if HI(refcyc) {
    SignalEvt(dsf, ZERO, s->dt_dsf);
    BundleEvt(Ndt, 3, s->dt_dt);
    BundleEvt(Nwe, 3, s->dt_we);
  } else {
    if HI(colmux) { /* CAS time */
      SignalEvt(dsf, ZERO, s->dt_dsf);
      if (write) {
        BundleEvt(Ndt, 3, s->dt_dt);
        if ((add_l & 4) && (BINVAL(ramc) & 2)) {
          BundleEvt(Nwe, 1, s->dt_we);
        } else {
          BundleEvt(Nwe, 2, s->dt_we);
        }
      } else {
        if ((add_l & 4) && (BINVAL(ramc) & 2)) {
          BundleEvt(Ndt, 1, s->dt_dt);
        } else {
          BundleEvt(Ndt, 2, s->dt_dt);
        }
        BundleEvt(Nwe, 3, s->dt_we);
      }
    } else { /* RAS time */
      if (HI(dmagoing) && (BINVAL(dmach) == TRANDMA)) {
        SignalEvt(dsf, HI(split), s->dt_dsf);
        BundleEvt(Ndt, 0, s->dt_dt);
      } else {
        SignalEvt(dsf, ZERO, s->dt_dsf);
        BundleEvt(Ndt, 3, s->dt_dt);
      }
      BundleEvt(Nwe, 3, s->dt_we);
    }
  }

/* Refresh requester counter */

  if LO(Ninit) { /* Asynchronous reset */
    s->refcount = 0;
    s->refrq = 0;
  } else {
    if RISING(clk32) {
      if HI(refcres) s->refcount=0; else
        s->refcount = (s->refcount + 1) & 0xfff;
      if (s->vrefcr & 1) s->refcount = (s->refcount & 0x1ff);
      if ((s->refcount == 0) && (s->vrefcr & 0xf)) s->refrq = TRUE; else {
        if (HI(dmagoing) && (BINVAL(dmach) == REFDMA)) 
          s->refrq = FALSE;
      }
    }
  }
  if FALLING(rclk) {
    if (s->refrq) 
     SignalEvt(refrq, ONE, NS*7);
    else
      SignalEvt(refrq, ZERO, NS*7);
  }
}

/*-------------- RAMCTLC Model Initialisation -----------------*/

static void RAMCTLC_init(void *ModelInst) {
  RAMCTLCState *s;
  ModelOfRAMCTLC *me = (ModelOfRAMCTLC *)ModelInst;
  NEW(s, RAMCTLCState);
  me->model.proc = RAMCTLC_proc;
  s->dt_ras = DELAY("ras");
  s->dt_cas = DELAY("cas");
  s->dt_we  = DELAY("we");
  s->dt_dt  = DELAY("dt");
  s->dt_dsf = DELAY("dsf");
  s->dt_regs = DELAY("regs");
  s->dt_ramc = DELAY("ramc");
  me->model.state = (void *)s;
}

void RAMCTLC_declare() {
  simmodel_begin("iomd.ramctlc");
  simmodel_declare_s(RAMCTLC_def,      RAMCTLC_init);
  simmodel_end();
}
